自写保护壳交流——指令的膨胀和花指令的插入
从准备写壳到到现在已经有半年多的时间了,期间代码框架重构了很多次。
总体架构共有三部分:PE部分、混淆虚拟化部分、保护部分。
目前 PE部分只写了简单的操作,没有对代码段的压缩和对导入表的处理。虚拟化部分,框架大概写蹦了5、6次(目前可以做到简单指令的模拟和对重定位的支持)最近一次是在2个月以前,将架构改成vmp 3.x的链式寻址的时候,又写蹦了框架,现在还没有整合。
本帖就说一下近期在写的混淆部分:
目前在写代码混淆膨胀部分,目前的设定框架是由3块组成:
1. 代码块的拆分
2. 全局地址管理器
3. 混淆过程
一、代码块的拆分
二、混淆地址管理器
混淆地址管理器,也叫全局地址管理器,因为vm框架也是用这个地址管理器。 在代码混淆过程中,你并不知道接下来的代码区块将会被膨胀到多大,所以必须要一个地址管理器来确定下一区块的大小。
首先要将地址分块,按照去除重定位(401000 处加载基址)的方式分配地址:
代码块1:address 0x40B016
代码块2:address xxx
代码块3:address xxx
使用地址管理器将代码块的地方分配并连接起来达到如下效果:
混淆分块后效果图:
三、混淆过程步骤
使用 代码块的拆分+地址管理器 -> 将代码块划分成一个个小的地址快来进行管理
首先划分区块,并将区块打上属性标签。
1. 区块划分
[DBGLOG]:代码块0,区块属性 JCC
mov eax, 0x1
cmp eax, 0x2
jz 0x40100e
[DBGLOG]:代码块1,区块属性 NULL
add eax, 0x1
inc eax
[DBGLOG]:代码块2,区块属性 JCC
mov eax, eax
add eax, 0x1
cmp eax, 0x1
jnz 0x40101d
[DBGLOG]:代码块3,区块属性 NULL
mov eax, eax
add eax, 0x1
[DBGLOG]:代码块4,区块属性 JCC
add eax, 0x1
dec eax
cmp eax, 0x2
jz 0x40102b
[DBGLOG]:代码块5,区块属性 NULL
mov eax, eax
add eax, 0x1
[DBGLOG]:代码块6,区块属性 JCC
mov eax, eax
mov eax, eax
dec eax
cmp eax, 0x3
jnz 0x40103a
[DBGLOG]:代码块7,区块属性 NULL
mov eax, eax
add eax, 0x1
[DBGLOG]:代码块8,区块属性 End
sub eax, 0x1
mov eax, eax
2. 将代码区块使用地址管理器分配地址:
[DBGLOG] 地址:00401000,代码块:0
[DBGLOG] 地址:0040100a,代码块:1
[DBGLOG] 地址:0040100e,代码块:2
[DBGLOG] 地址:00401018,代码块:3
[DBGLOG] 地址:0040101d,代码块:4
[DBGLOG] 地址:00401026,代码块:5
[DBGLOG] 地址:0040102b,代码块:6
[DBGLOG] 地址:00401035,代码块:7
[DBGLOG] 地址:0040103a,代码块:8
3. 添加简易重定位支持
这里对于混淆引擎来说使用到的全局变量应该交由PE部分去处理,但我这边偷懒直接使用vmp的重定位方式(/尴尬)
4. 指令处理
对于混淆虚拟化来说代码的本质是等价替换,这里以举一个最简单的例子 push 0x123456 :
我的方式 主要是对0x123456 进行处理,首先拿到0x123456 这个立即数 对0x123456进行加法,
异或 等操作 imm = ( 0x123456+0x111111 ) ^ 0x22222 = 0x216745在混淆代码中表现出来:
push eax
mov eax,imm
xor eax,0x22222
sub eax,0x111111
push eax
mov eax,dword ptr[esp+0x4]
这样就完成了 对 push 0x123456 指令的混淆。
5. 花指令的插入
在全局 有一个控制花指令插入的开关 _flower_code 由它决定是否插入花指令,部分代码如下:
void CodeObfuscationEngine::_insert_flower_code(asmjit::X86Assembler *& _a)
{
if (_insert_junk_code_number % 100 > _flower_code)
return;
int r = rand() % 3;
switch (r)
{
case 0:
{
Label label = _a->newLabel();
_a->jmp(label);
_a->db(0xE8);
_a->bind(label);
}break;
case 1:
{
Label label = _a->newLabel();
_a->jmp(label);
_a->db(0xE9);
_a->bind(label);
}break;
case 2:
{
Label label = _a->newLabel();
int addr = rand() % 0x66 + 0x5;
_a->call(label);
_a->db(0x74);
_a->db(addr);
_a->bind(label);
_a->add(esp, 4);
}break;
default:
break;
}
正常代码块:
代码块拆分:
代码混淆部分+花部分 :
里面去除了对某些指令的膨胀(比方xor)相对比较简单,新手项可以看未加壳部分,要求是逆出key
CrackMe :
Crackme_pack.exe(点击左下角阅读原文下载)
原始的未混淆部分:
Crackme_原始.exe(点击左下角阅读原文下载)
写在最后:
自己的工程参考了很多很多代码(多到我也记不清了,就不一一署名),先谢谢前辈们无私的奉献。
- End -
看雪ID:Wszzy
https://bbs.pediy.com/user-770239.htm
本文由看雪论坛 Wszzy 原创
转载请注明来自看雪社区
戳
热门文章阅读
公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com